package com.keba.basic.encrypt.config;

import com.keba.basic.encrypt.advice.DecryptRequestAdvice;
import com.keba.basic.encrypt.advice.EncryptResponseAdvice;
import com.keba.basic.encrypt.annotation.Security;
import com.keba.basic.encrypt.annotation.Sensitive;
import com.keba.basic.encrypt.aspect.SecurityAspect;
import com.keba.basic.encrypt.codec.*;
import com.keba.basic.encrypt.config.properties.SecurityProperties;
import com.keba.basic.encrypt.filter.SecurityRequestFilter;
import com.keba.basic.encrypt.format.CommonSensitiveProcessor;
import com.keba.basic.encrypt.format.SensitiveProcessor;
import com.keba.basic.encrypt.handler.CommonSecurityHandler;
import com.keba.basic.encrypt.handler.CommonSensitiveHandler;
import com.keba.basic.encrypt.handler.SecurityHandler;
import com.keba.basic.encrypt.handler.SensitiveHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * @author ls
 * @since 2023-07-21
 */
@Configuration
@ConditionalOnWebApplication //web应用生效
@EnableConfigurationProperties({SecurityProperties.class})
@Slf4j
@AllArgsConstructor
public class EncryptAutoConfiguration {
    /**
     * {@link SecurityProperties}
     */
    private final SecurityProperties securityProperties;


    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "lamp.security", name = "type", havingValue = "AES", matchIfMissing = true)
    public SecurityProcessor aesProcessor() {
        return new AESProcessor(securityProperties.getSecret());
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "lamp.security", name = "type", havingValue = "RSA")
    public SecurityProcessor rsaProcessor() {
        return new RSAProcessor(securityProperties.getPublicKey(), securityProperties.getPrivateKey());
    }

//    @Bean
//    @ConditionalOnMissingBean
//    @ConditionalOnProperty(prefix = "lamp.security", name = "type", havingValue = "SM4")
//    public SecurityProcessor sm4Processor() {
//        return new SM4Processor(securityProperties.getSecret());
//    }

//    @Bean
//    @ConditionalOnMissingBean
//    @ConditionalOnProperty(prefix = "lamp.security", name = "type", havingValue = "SM2")
//    public SecurityProcessor sm2Processor() {
//        return new SM2Processor(securityProperties.getPublicKey(), securityProperties.getPrivateKey());
//    }

    @Bean
    @ConditionalOnMissingBean
    public SecurityHandler<Security> commonSecurityHandler(@Autowired SecurityProcessor securityProcessor) {
        log.debug("encrypt-starter loading SecurityProcessor: {}", securityProcessor.getClass().getName());
        return new CommonSecurityHandler(securityProcessor, securityProperties.getMode(), securityProperties.getCharset());
    }

    @Bean
    @ConditionalOnMissingBean
    public SensitiveProcessor commonSensitiveProcessor() {
        return new CommonSensitiveProcessor();
    }

    @Bean
    @ConditionalOnMissingBean
    public SensitiveHandler<Sensitive> commonSensitiveHandler(@Autowired SensitiveProcessor commonSensitiveProcessor) {
        log.debug("encrypt-starter loading SensitiveHandler: {}", commonSensitiveProcessor.getClass().getName());
        return new CommonSensitiveHandler(commonSensitiveProcessor);
    }


    @Bean
    @ConditionalOnMissingBean
    public DecryptRequestAdvice decryptRequestAdvice() {
        return new DecryptRequestAdvice(securityProperties.getMaxDeep(), securityProperties.getClassPackage());
    }

    @Bean
    @ConditionalOnMissingBean
    public EncryptResponseAdvice encryptResponseAdvice() {
        List<String> classPackage = securityProperties.getClassPackage();
        log.debug("encrypt-starter scan class packages: {}", classPackage);
        return new EncryptResponseAdvice(securityProperties.getMaxDeep(), classPackage);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "lamp.security", name = "enable", havingValue = "true")
    public SecurityAspect securityAspect(@Autowired DecryptRequestAdvice decryptRequestAdvice,
                                         @Autowired EncryptResponseAdvice encryptResponseAdvice) {
        return new SecurityAspect(decryptRequestAdvice, encryptResponseAdvice);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "lamp.security", name = "enable", havingValue = "true")
    public SecurityRequestFilter securityRequestFilter(@Autowired SecurityProcessor securityProcessor) {
        return new SecurityRequestFilter(securityProcessor);
    }

}
